package com.datagateway.component;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 内存管理器
 * 负责内存监控、自动清理和优化建议
 * 
 * @author Data Gateway Team
 * @version 1.0.0
 */
@Component
public class MemoryManager {

    private static final Logger logger = LoggerFactory.getLogger(MemoryManager.class);

    @Autowired
    private AlertManager alertManager;

    @Autowired
    private SystemMonitor systemMonitor;

    /**
     * 内存使用统计
     */
    private final AtomicLong totalMemoryAllocated = new AtomicLong(0);
    private final AtomicLong totalMemoryFreed = new AtomicLong(0);
    private final AtomicLong totalGcCount = new AtomicLong(0);
    private final AtomicLong totalGcTime = new AtomicLong(0);

    /**
     * 内存阈值配置
     */
    private static final double HEAP_USAGE_WARN_THRESHOLD = 75.0;
    private static final double HEAP_USAGE_CRITICAL_THRESHOLD = 85.0;
    private static final double NON_HEAP_USAGE_WARN_THRESHOLD = 80.0;
    private static final double NON_HEAP_USAGE_CRITICAL_THRESHOLD = 90.0;

    /**
     * 内存池监控
     */
    private final ConcurrentHashMap<String, MemoryPoolInfo> memoryPools = new ConcurrentHashMap<>();

    /**
     * 自动清理配置
     */
    private boolean autoCleanupEnabled = true;
    private long cleanupInterval = 300000; // 5分钟
    private double cleanupThreshold = 80.0; // 80%内存使用率触发清理

    /**
     * 内存优化建议
     */
    private final AtomicReference<String> lastOptimizationSuggestion = new AtomicReference<>("");

    /**
     * 内存监控 - 每30秒执行一次
     */
    @Scheduled(fixedDelay = 30000)
    public void monitorMemory() {
        try {
            // 监控堆内存
            monitorHeapMemory();
            
            // 监控非堆内存
            monitorNonHeapMemory();
            
            // 监控内存池
            monitorMemoryPools();
            
            // 监控GC情况
            monitorGarbageCollection();
            
            // 执行自动清理
            if (autoCleanupEnabled) {
                performAutoCleanup();
            }
            
            // 生成优化建议
            generateOptimizationSuggestions();
            
        } catch (Exception e) {
            logger.error("内存监控异常", e);
            alertManager.sendSystemErrorAlert("内存监控异常", e.getMessage());
        }
    }

    /**
     * 监控堆内存
     */
    private void monitorHeapMemory() {
        try {
            MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
            MemoryUsage heapMemory = memoryBean.getHeapMemoryUsage();
            
            long used = heapMemory.getUsed();
            long max = heapMemory.getMax();
            long committed = heapMemory.getCommitted();
            
            double usagePercent = (double) used / max * 100;
            
            logger.debug("堆内存监控: 使用={} MB, 最大={} MB, 已提交={} MB, 使用率={:.2f}%", 
                        used / 1024 / 1024, max / 1024 / 1024, committed / 1024 / 1024, usagePercent);
            
            // 堆内存使用率告警
            if (usagePercent > HEAP_USAGE_CRITICAL_THRESHOLD) {
                alertManager.sendMemoryUsageAlert(used, max, usagePercent);
            } else if (usagePercent > HEAP_USAGE_WARN_THRESHOLD) {
                alertManager.sendMemoryUsageAlert(used, max, usagePercent);
            }
            
        } catch (Exception e) {
            logger.error("监控堆内存失败", e);
        }
    }

    /**
     * 监控非堆内存
     */
    private void monitorNonHeapMemory() {
        try {
            MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
            MemoryUsage nonHeapMemory = memoryBean.getNonHeapMemoryUsage();
            
            long used = nonHeapMemory.getUsed();
            long max = nonHeapMemory.getMax();
            long committed = nonHeapMemory.getCommitted();
            
            double usagePercent = max > 0 ? (double) used / max * 100 : 0;
            
            logger.debug("非堆内存监控: 使用={} MB, 最大={} MB, 已提交={} MB, 使用率={:.2f}%", 
                        used / 1024 / 1024, max / 1024 / 1024, committed / 1024 / 1024, usagePercent);
            
            // 非堆内存使用率告警
            if (usagePercent > NON_HEAP_USAGE_CRITICAL_THRESHOLD) {
                alertManager.sendPerformanceAlert("非堆内存使用率", usagePercent, NON_HEAP_USAGE_CRITICAL_THRESHOLD);
            } else if (usagePercent > NON_HEAP_USAGE_WARN_THRESHOLD) {
                alertManager.sendPerformanceAlert("非堆内存使用率", usagePercent, NON_HEAP_USAGE_WARN_THRESHOLD);
            }
            
        } catch (Exception e) {
            logger.error("监控非堆内存失败", e);
        }
    }

    /**
     * 监控内存池
     */
    private void monitorMemoryPools() {
        try {
            List<MemoryPoolMXBean> memoryPools = ManagementFactory.getMemoryPoolMXBeans();
            
            for (MemoryPoolMXBean pool : memoryPools) {
                String poolName = pool.getName();
                MemoryUsage usage = pool.getUsage();
                
                if (usage != null) {
                    long used = usage.getUsed();
                    long max = usage.getMax();
                    long committed = usage.getCommitted();
                    
                    double usagePercent = max > 0 ? (double) used / max * 100 : 0;
                    
                    // 更新内存池信息
                    MemoryPoolInfo poolInfo = new MemoryPoolInfo(
                        poolName,
                        used,
                        max,
                        committed,
                        usagePercent,
                        pool.getType().toString(),
                        System.currentTimeMillis()
                    );
                    
                    this.memoryPools.put(poolName, poolInfo);
                    
                    logger.debug("内存池监控: {} - 使用={} MB, 最大={} MB, 使用率={:.2f}%", 
                                poolName, used / 1024 / 1024, max / 1024 / 1024, usagePercent);
                }
            }
            
        } catch (Exception e) {
            logger.error("监控内存池失败", e);
        }
    }

    /**
     * 监控垃圾回收
     */
    private void monitorGarbageCollection() {
        try {
            List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
            
            long totalGcCount = 0;
            long totalGcTime = 0;
            
            for (GarbageCollectorMXBean gcBean : gcBeans) {
                totalGcCount += gcBean.getCollectionCount();
                totalGcTime += gcBean.getCollectionTime();
                
                logger.debug("GC监控: {} - 次数={}, 时间={} ms", 
                            gcBean.getName(), gcBean.getCollectionCount(), gcBean.getCollectionTime());
            }
            
            // 更新统计信息
            this.totalGcCount.set(totalGcCount);
            this.totalGcTime.set(totalGcTime);
            
        } catch (Exception e) {
            logger.error("监控垃圾回收失败", e);
        }
    }

    /**
     * 执行自动清理
     */
    private void performAutoCleanup() {
        try {
            MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
            MemoryUsage heapMemory = memoryBean.getHeapMemoryUsage();
            
            long used = heapMemory.getUsed();
            long max = heapMemory.getMax();
            double usagePercent = (double) used / max * 100;
            
            if (usagePercent > cleanupThreshold) {
                logger.info("内存使用率超过阈值，执行自动清理: {:.2f}% > {:.2f}%", usagePercent, cleanupThreshold);
                
                // 执行系统GC
                System.gc();
                
                // 清理内存池信息
                cleanupMemoryPoolInfo();
                
                // 发送清理通知
                alertManager.sendSystemInfoAlert("内存自动清理", 
                    String.format("内存使用率: %.2f%%, 已执行自动清理", usagePercent));
                
                // 记录清理统计
                totalMemoryFreed.addAndGet(used - heapMemory.getUsed());
            }
            
        } catch (Exception e) {
            logger.error("执行自动清理失败", e);
        }
    }

    /**
     * 清理内存池信息
     */
    private void cleanupMemoryPoolInfo() {
        try {
            long currentTime = System.currentTimeMillis();
            long cleanupThreshold = 300000; // 5分钟
            
            memoryPools.entrySet().removeIf(entry -> {
                MemoryPoolInfo poolInfo = entry.getValue();
                return (currentTime - poolInfo.getTimestamp()) > cleanupThreshold;
            });
            
            logger.debug("内存池信息清理完成，当前内存池数量: {}", memoryPools.size());
            
        } catch (Exception e) {
            logger.error("清理内存池信息失败", e);
        }
    }

    /**
     * 生成优化建议
     */
    private void generateOptimizationSuggestions() {
        try {
            MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
            MemoryUsage heapMemory = memoryBean.getHeapMemoryUsage();
            MemoryUsage nonHeapMemory = memoryBean.getNonHeapMemoryUsage();
            
            long usedHeap = heapMemory.getUsed();
            long maxHeap = heapMemory.getMax();
            long usedNonHeap = nonHeapMemory.getUsed();
            
            double heapUsagePercent = (double) usedHeap / maxHeap * 100;
            
            StringBuilder suggestions = new StringBuilder();
            
            // 堆内存优化建议
            if (heapUsagePercent > 80) {
                suggestions.append("堆内存使用率过高，建议增加堆内存大小或优化内存使用; ");
            }
            
            // 非堆内存优化建议
            if (usedNonHeap > 200 * 1024 * 1024) { // 200MB
                suggestions.append("非堆内存使用过多，建议检查元空间或代码缓存使用情况; ");
            }
            
            // GC优化建议
            long uptime = ManagementFactory.getRuntimeMXBean().getUptime();
            double gcTimePercent = uptime > 0 ? (double) totalGcTime.get() / uptime * 100 : 0;
            
            if (gcTimePercent > 10) {
                suggestions.append("GC时间占比过高，建议优化GC配置或减少对象创建; ");
            }
            
            // 内存池优化建议
            for (MemoryPoolInfo poolInfo : memoryPools.values()) {
                if (poolInfo.getUsagePercent() > 90) {
                    suggestions.append(String.format("内存池 %s 使用率过高: %.2f%%, 建议优化; ", 
                                                   poolInfo.getName(), poolInfo.getUsagePercent()));
                }
            }
            
            String suggestion = suggestions.toString();
            if (!suggestion.isEmpty()) {
                lastOptimizationSuggestion.set(suggestion);
                logger.info("内存优化建议: {}", suggestion);
            }
            
        } catch (Exception e) {
            logger.error("生成优化建议失败", e);
        }
    }

    /**
     * 获取内存使用情况
     * 
     * @return 内存使用情况
     */
    public MemoryUsageInfo getMemoryUsage() {
        try {
            MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
            MemoryUsage heapMemory = memoryBean.getHeapMemoryUsage();
            MemoryUsage nonHeapMemory = memoryBean.getNonHeapMemoryUsage();
            
            return new MemoryUsageInfo(
                heapMemory.getUsed(),
                heapMemory.getMax(),
                heapMemory.getCommitted(),
                nonHeapMemory.getUsed(),
                nonHeapMemory.getMax(),
                nonHeapMemory.getCommitted(),
                System.currentTimeMillis()
            );
            
        } catch (Exception e) {
            logger.error("获取内存使用情况失败", e);
            return new MemoryUsageInfo(0, 0, 0, 0, 0, 0, System.currentTimeMillis());
        }
    }

    /**
     * 获取内存统计信息
     * 
     * @return 内存统计信息
     */
    public MemoryStatistics getStatistics() {
        return new MemoryStatistics(
            totalMemoryAllocated.get(),
            totalMemoryFreed.get(),
            totalGcCount.get(),
            totalGcTime.get(),
            memoryPools.size(),
            lastOptimizationSuggestion.get(),
            System.currentTimeMillis()
        );
    }

    /**
     * 获取内存池信息
     * 
     * @return 内存池信息映射
     */
    public ConcurrentHashMap<String, MemoryPoolInfo> getMemoryPools() {
        return new ConcurrentHashMap<>(memoryPools);
    }

    /**
     * 设置自动清理配置
     * 
     * @param enabled 是否启用自动清理
     * @param interval 清理间隔（毫秒）
     * @param threshold 清理阈值（百分比）
     */
    public void setAutoCleanupConfig(boolean enabled, long interval, double threshold) {
        this.autoCleanupEnabled = enabled;
        this.cleanupInterval = interval;
        this.cleanupThreshold = threshold;
        logger.info("自动清理配置已更新: 启用={}, 间隔={} ms, 阈值={}%", enabled, interval, threshold);
    }

    /**
     * 手动触发内存清理
     */
    public void triggerMemoryCleanup() {
        try {
            logger.info("手动触发内存清理");
            
            // 执行系统GC
            System.gc();
            
            // 清理内存池信息
            cleanupMemoryPoolInfo();
            
            // 记录清理统计
            MemoryUsageInfo usage = getMemoryUsage();
            totalMemoryFreed.addAndGet(usage.getUsedHeap());
            
            logger.info("内存清理完成");
            
        } catch (Exception e) {
            logger.error("手动触发内存清理失败", e);
        }
    }

    /**
     * 内存使用信息类
     */
    public static class MemoryUsageInfo {
        private final long usedHeap;
        private final long maxHeap;
        private final long committedHeap;
        private final long usedNonHeap;
        private final long maxNonHeap;
        private final long committedNonHeap;
        private final long timestamp;

        public MemoryUsageInfo(long usedHeap, long maxHeap, long committedHeap,
                             long usedNonHeap, long maxNonHeap, long committedNonHeap, long timestamp) {
            this.usedHeap = usedHeap;
            this.maxHeap = maxHeap;
            this.committedHeap = committedHeap;
            this.usedNonHeap = usedNonHeap;
            this.maxNonHeap = maxNonHeap;
            this.committedNonHeap = committedNonHeap;
            this.timestamp = timestamp;
        }

        // Getter方法
        public long getUsedHeap() { return usedHeap; }
        public long getMaxHeap() { return maxHeap; }
        public long getCommittedHeap() { return committedHeap; }
        public long getUsedNonHeap() { return usedNonHeap; }
        public long getMaxNonHeap() { return maxNonHeap; }
        public long getCommittedNonHeap() { return committedNonHeap; }
        public long getTimestamp() { return timestamp; }
        
        public double getHeapUsagePercent() { return maxHeap > 0 ? (double) usedHeap / maxHeap * 100 : 0; }
        public double getNonHeapUsagePercent() { return maxNonHeap > 0 ? (double) usedNonHeap / maxNonHeap * 100 : 0; }
    }

    /**
     * 内存池信息类
     */
    public static class MemoryPoolInfo {
        private final String name;
        private final long used;
        private final long max;
        private final long committed;
        private final double usagePercent;
        private final String type;
        private final long timestamp;

        public MemoryPoolInfo(String name, long used, long max, long committed, 
                            double usagePercent, String type, long timestamp) {
            this.name = name;
            this.used = used;
            this.max = max;
            this.committed = committed;
            this.usagePercent = usagePercent;
            this.type = type;
            this.timestamp = timestamp;
        }

        // Getter方法
        public String getName() { return name; }
        public long getUsed() { return used; }
        public long getMax() { return max; }
        public long getCommitted() { return committed; }
        public double getUsagePercent() { return usagePercent; }
        public String getType() { return type; }
        public long getTimestamp() { return timestamp; }
    }

    /**
     * 内存统计信息类
     */
    public static class MemoryStatistics {
        private final long totalMemoryAllocated;
        private final long totalMemoryFreed;
        private final long totalGcCount;
        private final long totalGcTime;
        private final int memoryPoolCount;
        private final String lastOptimizationSuggestion;
        private final long timestamp;

        public MemoryStatistics(long totalMemoryAllocated, long totalMemoryFreed, long totalGcCount,
                              long totalGcTime, int memoryPoolCount, String lastOptimizationSuggestion, long timestamp) {
            this.totalMemoryAllocated = totalMemoryAllocated;
            this.totalMemoryFreed = totalMemoryFreed;
            this.totalGcCount = totalGcCount;
            this.totalGcTime = totalGcTime;
            this.memoryPoolCount = memoryPoolCount;
            this.lastOptimizationSuggestion = lastOptimizationSuggestion;
            this.timestamp = timestamp;
        }

        // Getter方法
        public long getTotalMemoryAllocated() { return totalMemoryAllocated; }
        public long getTotalMemoryFreed() { return totalMemoryFreed; }
        public long getTotalGcCount() { return totalGcCount; }
        public long getTotalGcTime() { return totalGcTime; }
        public int getMemoryPoolCount() { return memoryPoolCount; }
        public String getLastOptimizationSuggestion() { return lastOptimizationSuggestion; }
        public long getTimestamp() { return timestamp; }
    }
}
